<template>
	<view class="QS-Form" ref="QS-Form" :class="getClass" :style="getStyle">
		<slot></slot>
	</view>
</template>

<script>
	import QSComponentMixin from '../../mixins/QS-Components-Mixin.js';
	import validate from '../../js/QS-Form/js/validate.js';
	import { isPromise, isArray, isObject } from '../../js/baseUtil.js';
	let props;
	try{
		props = require('@/QS-UI-CONFIG/components/QS-Form/js/props.js');
	}catch(e){
		//TODO handle the exception
		props = {};
	}
	
	const componentType = 'QS-Form';
	const QSComponentMixinRes = QSComponentMixin({ 
		componentType,
		nodeName: '.QS-Form'
	});
	const forms = {};
	const example = function () {
		return {
			name: componentType,
			mixins: [
				QSComponentMixinRes.mixin,
			],
			provide() {
				return {
					QSForm: this
				}
			},
			props: {
				// #ifdef MP-ALIPAY
				...QSComponentMixinRes.props,
				// #endif
				validateFunction: Function,
				rules: {
					type: [Object, Array],
					default: ()=>null
				},
				labelWidth: {
					type: [String, Number],
					default: 'auto'
				},
				labelPosition: {
					type: String,
					default: 'left'
				},
				validateStateFixed: {
					type: [String, Boolean],
					default: ''
				},
				...props,
				dynamicForm: {
					type: Boolean,
					default: false
				}
			},
			computed: {
				getRequireds() {
					if(this.rules && typeof this.rules == 'object') {
						return Object.keys(this.rules).filter(i=>{
							const item = this.rules[i];
							if(isArray(item)) {
								return -1 != item.findIndex(it=>it.required)
							}else{
								return item.required;
							}
						})
					}
					return [];
				}
			},
			created() {
				forms[this.componentId] = {};
				forms[this.componentId].elObjs = [];
				forms[this.componentId].itemsObj = [];
			},
			beforeDestroy() {
				try{
					delete forms[this.componentId];
				}catch(e){
					//TODO handle the exception
				}
			},
			methods: {
				setElObjs(elObjs) {
					if(!forms[this.componentId]) forms[this.componentId] = {};
					forms[this.componentId].elObjs = elObjs;
				},
				setItemsObj(itemsObj) {
					if(!forms[this.componentId]) forms[this.componentId] = {};
					forms[this.componentId].itemsObj = itemsObj;
				},
				setItem(item) {
					// #ifdef MP-ALIPAY
					if(this.dynamicForm) return;
					// #endif
					if(-1 == forms[this.componentId].elObjs.findIndex(i=>i==item)) {
						forms[this.componentId].elObjs.push(item)
					}
				},
				removeItem(item) {
					// #ifdef MP-ALIPAY
					if(this.dynamicForm) return;
					// #endif
					if(!forms[this.componentId]?.elObjs) return;
					const ind = forms[this.componentId].elObjs.findIndex(i=>i==item);
					if(-1 != ind) {
						forms[this.componentId].elObjs.splice(ind, 1);
					}
				},
				setFormItem(formItem) {
					// #ifdef MP-ALIPAY
					if(this.dynamicForm) return;
					// #endif
					if(-1 == forms[this.componentId].itemsObj.findIndex(i=>i==formItem)) {
						forms[this.componentId].itemsObj.push(formItem)
					}
				},
				removeFormItem(formItem) {
					// #ifdef MP-ALIPAY
					if(this.dynamicForm) return;
					// #endif
					if(!forms[this.componentId]?.itemsObj) return;
					const ind = forms[this.componentId].itemsObj.findIndex(i=>i==formItem);
					if(-1 != ind) {
						forms[this.componentId].itemsObj.splice(ind, 1);
					}
				},
				clearValidateState() {
					forms[this.componentId].itemsObj.forEach(i=>i.setValidateState({ validateStatus: true }));
				},
				submit(e) {
					return new Promise((rs, rj)=>{
						this.clearValidateState();
						const formData = {};
						const promiseArr = forms[this.componentId].elObjs.map(i=>{
							return new Promise(async (resolve, reject)=>{
								if(!i.prop) {
									resolve();
									return;
								}
								let value = i.getValue(), rules = [], formRules, formItem;
								if(isPromise(value)) value = await value;
								const elRules = i.getRules();
								if(this.rules && isObject(this.rules)) {
									const propRules = this.rules[i.prop];
									if(propRules) {
										if(isArray(propRules)) formRules = propRules;
										else formRules = [propRules];
									}
								}
								
								if(forms[this.componentId]?.itemsObj?.length) {
									formItem = forms[this.componentId].itemsObj.find(it=>it.getEl().includes(i));
								}
								if(formItem?.getRequired) {
									if(!rules.find(i=>i.required)) rules.push({ required: true });
								}
								
								if(formRules && !elRules) rules = rules.concat(formRules);
								else if(!formRules && elRules) rules = rules.concat(elRules);
								else if(formRules && elRules) rules = rules.concat([...formRules, ...elRules]);
								
								if(rules && rules.length) {
									if(typeof rules == 'object') {
										let validateResult = validate({ prop: i.prop, value: value, rules: rules, label: i.getLabel() || i.prop});
										
										if(isPromise(validateResult)) validateResult = await validateResult;
										if(!validateResult?.result) {
											i.setValidateState && i.setValidateState({ validateStatus: false, validateMessage: validateResult.message });
											reject(validateResult);
											return;
										}
									}else{
										console.log('rule需为Object类型');
										console.warn('rule需为Object类型');
									}
								}
								
								if(this.validateFunction && typeof this.validateFunction == 'function') {
									let validateFunctionResult = this.validateFunction({ prop: i.prop, value: value, rules: rules, label: i.getLabel() || i.prop});
									if(isPromise(validateFunctionResult)) validateFunctionResult = await validateFunctionResult;
									if(isObject(validateFunctionResult)) {
										if(!validateFunctionResult?.result) {
											i.setValidateState && i.setValidateState({ validateStatus: false, validateMessage: validateFunctionResult.message });
											reject(validateFunctionResult);
											return
										}
									}
								}
								
								formData[i.prop] = value;
								resolve();
							}) 
						});
						return Promise.all(promiseArr)
							.then(res=>{
								rs(formData)
							})
							.catch(err=>{
								rj(err);
							})
					})
				},
				getFieldRule(prop) {
					if(!prop) {
						console.log('getFieldRule: prop不能为空');
						console.warn('getFieldRule: prop不能为空');
						return;
					}
					return this?.rules?.[prop];
				},
				reset(e) {
					this.$emit('reset', e)
				}
			}
		}
	}
	export default example();
</script>

<style scoped>
</style>
